package com.sz.common.pay.pingan.core.server;

import com.sz.common.pay.common.PayLogger;
import com.sz.common.pay.pingan.constant.Constant;
import com.sz.common.pay.pingan.constant.ResponseCode;
import com.sz.common.pay.pingan.entity.common.CommonHeadResponse;
import com.sz.common.pay.pingan.exception.OperationFailedException;
import com.sz.common.pay.pingan.exception.PayCommonException;
import com.sz.common.pay.pingan.util.CharSetUtil;
import com.sz.common.pay.pingan.util.PayExceptionUtil;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.HashMap;

/**
 * Function: 银行请求企业系统时处理http请求数据 <br>
 *
 * @author: siqishangshu <br>
 * @date: 2017-12-19 11:41:00
 */
public class PAServer {
    private static final String UNKNOWN = "unknown";
    private static final String REGEX = ",";
    private static PayLogger payLogger = PayLogger.getLogger(PAServer.class);

    /**
     * 获取银行请求操作码
     *
     * @param sequence
     * @param tranMessage
     * @return
     * @throws PayCommonException
     */
    public static int getTranFunCode(String sequence, String tranMessage) throws PayCommonException {
        HttpRequestConverter httpRequestConverter = new HttpRequestConverter();
        int func = Integer.parseInt(httpRequestConverter.getTranFunCode(tranMessage));
        payLogger.info(sequence, "获取银行请求操作码 : " + func);
        return func;
    }


    /**
     * 获取请求对象实体
     *
     * @param sequence
     * @param clazz
     * @return
     * @throws OperationFailedException
     * @throws PayCommonException
     */
    public static Object getRequestInfo(String sequence, String tranMessage, Class clazz) throws OperationFailedException, PayCommonException {
        isVaildParam(sequence, clazz);
        HttpRequestConverter httpRequestConverter = new HttpRequestConverter();
        HashMap hashMap = httpRequestConverter.parsingTranMessage(sequence, tranMessage);
        Object object = ServerMapConverter.toObj(sequence, hashMap, clazz);
        payLogger.info(sequence, "获取银行请求操作数据 : " + object);
        return object;
    }

    /**
     * 写入响应数据
     *
     * @param sequence
     * @param response
     * @param httpServletResponse
     * @throws OperationFailedException
     * @throws PayCommonException
     */
    public static void writeResponse(String sequence, Object response, HttpServletResponse httpServletResponse, CommonHeadResponse commonHeadResponse) throws OperationFailedException, PayCommonException {
        isVaildParam(response, sequence, httpServletResponse, commonHeadResponse);
        payLogger.info(sequence, "封装银行响应数据 : " + response);
        httpServletResponse.addHeader("Content-Type", "application/octet-stream");
        String responseMessage = getResponse(sequence, response, commonHeadResponse);
        payLogger.info(sequence, "##############封装银行响应数据##############");
        payLogger.info(sequence, responseMessage);
        OutputStream outputStream = null;
        try {
            outputStream = httpServletResponse.getOutputStream();
            outputStream.write(responseMessage.getBytes(Constant.CHARSET_GBK));
            outputStream.flush();
        } catch (IOException e) {
            payLogger.error(sequence, "封装银行响应数据 : " + e.getMessage());
            throw new PayCommonException("写response数据异常");
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    payLogger.error(sequence, "封装银行响应数据 : " + response);
                    throw new PayCommonException("写response数据异常");
                }
            }
        }
    }

    /**
     * 验证是否是合法的请求IP
     *
     * @param request
     * @return
     */
    public static boolean VerifyLegitimateIP(HttpServletRequest request) {
        String[] ips = getIpAddr(request).split(REGEX);
        boolean legal = false;
        for (String ip : ips) {
            payLogger.info("B2B request IP: " + ip);
            for (String b2bip : Constant.B2BIPS) {
                if (b2bip.contains(ip)) {
                    legal = true;
                }
            }
        }
        return legal;
    }

    /**
     * 获取响应数据
     *
     * @param sequence
     * @param object
     * @return
     * @throws OperationFailedException
     * @throws PayCommonException
     */
    private static String getResponse(String sequence, Object object, CommonHeadResponse commonHeadResponse) throws OperationFailedException, PayCommonException {
        HttpResponseConverter httpResponseConverter = new HttpResponseConverter();
        return httpResponseConverter.getTranMessage(sequence, ServerMapConverter.toMap(commonHeadResponse, object, sequence));
    }

    /**
     * 获取请求的IP信息
     *
     * @param request
     * @return
     */
    private static String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || UNKNOWN.equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    /**
     * 获取银行请求数据
     *
     * @param sequence
     * @param request
     * @return
     */
    public static String readRequest(String sequence, HttpServletRequest request) throws PayCommonException {
            payLogger.info(sequence, "解析银行请求编码 " +request.getCharacterEncoding());
        if ((request.getContentLength() < 0)) {
            payLogger.error(sequence, "解析银行请求数据错误: Request Data is null");
            PayExceptionUtil.throwPayCommonException(sequence, "Request Data is null ", ResponseCode.ERR933);
        }
        byte[] bytes = new byte[request.getContentLength()];
        String message = null;
        try {
            InputStream inputStream = request.getInputStream();
            inputStream.read(bytes);
            message = CharSetUtil.getStringFromBytesToGBK(bytes);
        } catch (IOException e) {
            payLogger.error(sequence, "解析银行请求数据错误: " + e.getMessage());
            PayExceptionUtil.throwPayCommonException(sequence, e.getMessage(), ResponseCode.ERR933);
        }
        if ((message == null || "".equals(message))) {
            payLogger.error(sequence, "解析银行请求数据错误: Request Data is null");
            PayExceptionUtil.throwPayCommonException(sequence, "Request Data is null ", ResponseCode.ERR933);
        }
        payLogger.info(sequence, "##############解析银行请求数##############");
        payLogger.info(sequence, message);
        return message;
    }


    private static void isVaildParam(Object response, String sequence, HttpServletResponse httpServletResponse, CommonHeadResponse commonHeadResponse) throws PayCommonException {
        if (null == httpServletResponse || null == response || null == commonHeadResponse) {
            payLogger.error(sequence, "解析银行请求数据错误: data can't be null");
            PayExceptionUtil.throwPayCommonException(sequence, "data can't be null", ResponseCode.ERR030);
        }
        if (!response.getClass().getPackage().toString().contains(Constant.VAILD_PACKAGE)) {
            payLogger.error(sequence, "解析银行请求数据错误: data can't be null");
            PayExceptionUtil.throwPayCommonException(sequence, "request is not a vaild object", ResponseCode.ERR947);
        }
        if ((sequence.length() != Constant.THIRD_LOG_NO_LEN)) {
            payLogger.error(sequence, "解析银行请求数据错误: data can't be null");
            PayExceptionUtil.throwPayCommonException(sequence, "thirdLogNo is not a vaild value", ResponseCode.ERR935);
        }
    }

    private static void isVaildParam(String sequence, Class responseClazz) throws PayCommonException {
        if (!responseClazz.getPackage().toString().contains(Constant.VAILD_PACKAGE)) {
            payLogger.error(sequence, "解析银行请求数据错误: data can't be null");
            PayExceptionUtil.throwPayCommonException(sequence, "responseClazz is not a vaild clazz", ResponseCode.ERR947);
        }
        if ((sequence.length() != Constant.THIRD_LOG_NO_LEN)) {
            payLogger.error(sequence, "解析银行请求数据错误: data can't be null");
            PayExceptionUtil.throwPayCommonException(sequence, "thirdLogNo is not a vaild value", ResponseCode.ERR935);
        }
    }

}
